[array] leetCode-4-Median of Two Sorted Arrays-Hard

leetCode-4-Median of Two Sorted Arrays-Hard

descrition

There are two sorted arrays nums1 and nums2 of size m and n respectively.

Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).

example 1

nums1 = [1, 3]
nums2 = [2]

The median is 2.0

example 2

nums1 = [1, 2]
nums2 = [3, 4]

The median is (2 + 3)/2 = 2.5

解析

注意题目对时间复杂度的要求:O(log (m+n)),在加上数组有序的条件,此处应该联想到二分搜索的优化。那要如何用呢?看下面分析。(也可以参考 leetcode 中的 solution,解释得也很好)

定义函数接口:

double findMedianSortedArrays(vector<int>& A, vector<int>& B)

即两个数组 A, B,假设大小分别为 m 和 n

将数组 A 根据任意位置 i 分成左右两部分,同理 B 根据任意位置 j 也分成左右两部分,如下:

left_part                | right_part
A[0], A[1], ..., A[i-1]  | A[i], A[i+1], ... , A[m]  
B[0], B[1], ..., B[j-1]  | B[j], B[j+1], ... , B[n]

由中位数的定义以及数组有序的条件,我们希望以上划分满足:

len(left_part) = len(right_part) 
    ==> i+j = m-i + n-j (or: i+j = m-i + n-j + 1 (奇数的情况,将多的一个放到左边))
    ==> j = (m+n+1)/2 - i, i=[0,m]
max(left_part) <= min(right_part) ==> A[i-1] <= B[j] && B[j-1] <= A[i]

由此我们只需要在有序数组 A 上进行二分查找,确定 i 的位置,使得以上条件满足即可找到合适的划分。在此基础上我们可以根据划分边界求得 median。

初始条件:imin = 0, imax = m;
当 imin <= imax 时候的一次迭代: 
	i = (imin + imax) / 2
	j = (m+n+1)/2 - i
	// 此处讨论暂时不考虑边界情况,即假设 i 和 j 都合法
	// 只可能出现以下几种情况:
	(1) A[i-1] <= B[j] && B[j-1] <= A[i]
		// 划分满足要求,可以停止循环
	(2) A[i-1] > B[j] 
		// A[i-1] 太大,也就是我们要想办法调整 i 的值使得  A[i-1] <= B[j] 成立
		// 这个时候如果我们增大 i,只会使得 A[i-1] 更大 (因为数组是非递减有序的)
		// 因此我们只能通过减小 i,尝试找到更小的 A[i-1],因此作出如下调整
		imax = i-1
	(3)	B[j-1] > A[i]
		// B[j-1] 太大,同理我们应该减小 j
		// 从另一个角度,减小 j 就相当于增大 i,因此我们作出以下调整
		imin = i+1

几个细节:

  • m <= n 必须成立。因为 j = (m+n+1)/2 - i,如果 m>n,那么 j 将有可能为负数。因此在程序的开始进行检查。
  • 边界条件的讨论。当 i0, j0, im, jn 时,A[i-1], B[j-1], A[i], B[j] 都是不成立的。如果 i 和 j 都满足要求时,我们需要检查 A[i-1] <= B[j] && B[j-1] <= A[i] 是否成立,那么当 i 和 j 到达边界条件时,我们也就不需要检查其中的某一个条件,比如当 i == 0 时, A 数组的左边为空,我们就不需要检查 A[i-1] <= B[j] 这个条件。(参看代码)

code


#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

class Solution{
public:
	double findMedianSortedArrays(vector<int>& A, vector<int>& B){
		// insure the size of A is less than and equal to the size of B
		if(A.size() > B.size())
			swap(A, B);
		int m = A.size();
		int n = B.size();
		// m <= n

		// when m+n is odd, the follow equation will insure the median 
		// will be assined into left part. 
		int lenLeft = (m+n+1) / 2; 

		// binary search 
		int imin = 0, imax = m;
		while(imin <= imax){
			int i = (imin + imax) / 2;
			int j = lenLeft - i;
			if( i>0 && A[i-1] > B[j]){
				// A[i-1] too large, decreasing i
				// i > 0 ==> j<n, because j = (m+n+1) / 2 - i < (m+n+1) / 2 < 2n+1/2 < n
				imax = i-1;
			}else if ( i<m && B[j-1] > A[i]){
				// A[i] too small, increasing i
				// i < m ==> j>0, because j = (m+n+1) / 2 - i > (m+n+1) / 2 - m > (2m+1)/2 - m > 0
				imin = i+1;
			}else{
				// perfit
				int maxLeft = 0;
				if(i == 0){
					maxLeft = B[j-1];
				}else if (j == 0){
					maxLeft = A[i-1];
				}else{
					maxLeft = max(B[j-1], A[i-1]);
				}

				if( ((n+m)&1) == 1) // odd
					return maxLeft;

				int minRight = 0;
				if(i == m){
					minRight = B[j];
				}else if (j == n){
					minRight = A[i];
				}else{
					minRight = min(B[j], A[i]);
				}

				return (maxLeft + minRight)*1.0 / 2.0;
			}
		}

		return 0.0;
	}
};

int main()
{
	return 0;
}

posted @ 2017-11-11 00:11  .....?  阅读(293)  评论(0编辑  收藏  举报